#include "mainwindow.h"
#include "net.h"
#include "ui_mainwindow.h"
int   packetNum;
ipPack packList[999];

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    packetNum=0;

    ui->setupUi(this);
    this->setFixedSize(1200,800);
    tableInit();
    macInit(adhandle);



}

MainWindow::~MainWindow()
{
    delete ui;
}
/*下边实现tcp数据包分析的函数定义tcp_protocol_packet_callback*/
void  tcp_protocol_packet_callback(u_char *argument, const struct pcap_pkthdr*
                                   packet_header, const u_char* packet_content)
{

    qDebug()<<"tcpppp";
    struct tcp_header *tcp_protocol;     /*tcp协议变量*/
    tcp_protocol = (struct tcp_header *) (packet_content + 14 + 20);  /*获得tcp首部内容*/
    packList[packetNum].theader=tcp_protocol;


}
/*下边实现IP数据包分析的函数定义ethernet_protocol_packet_callback*/
void ip_protocol_packet_callback(u_char *argument, const struct pcap_pkthdr*
                                 packet_header, const u_char* packet_content)
{
    qDebug()<<"ipppppp";
    struct ip_header *ip_protocol;   /*ip协议变量*/

    ip_protocol = (struct ip_header*) (packet_content + 14); /*获得ip数据包的内容去掉以太头部*/
    packList[packetNum].iheader=ip_protocol;


    u_int  header_length;    /*长度*/
    u_int  offset;                   /*片偏移*/
    u_char  tos;                     /*服务类型*/
    u_int16_t checksum;    /*首部检验和*/


    cout << "\n传输层协议是:\t";
    tcp_protocol_packet_callback(argument, packet_header, packet_content);
//    switch (ip_protocol->ip_protocol)
//    {
//    case 6:
//        printf("TCP\n");
//        tcp_protocol_packet_callback(argument, packet_header, packet_content);
//        break; /*协议类型是6代表TCP*/
//    case 17:
//        printf("UDP\n");
//        break;/*17代表UDP*/
//    case 1:
//        printf("ICMP\n");
//        break;/*代表ICMP*/
//    case 2:
//        printf("IGMP\n");
//        break;/*代表IGMP*/
//    default:break;
//    }

}

void  ethernet_protocol_packet_callback(u_char *argument, const struct pcap_pkthdr *packet_header, const u_char* packet_content)
{
    packetNum++;

    qDebug()<<"eppppppp";
    u_short ethernet_type;                                     /*以太网协议类型*/
    struct ethernet_header *ethernet_protocol;  /*以太网协议变量*/
    u_char *mac_string;

    ethernet_protocol = (struct ethernet_header *) packet_content;  /*获得一太网协议数据内容*/
    packList[packetNum] = *new ipPack;
    packList[packetNum].eheader = new ethernet_header;
    packList[packetNum].iheader = new ip_header;
    packList[packetNum].theader = new tcp_header;

    packList[packetNum].eheader->ether_type=ethernet_protocol->ether_type;
    for(int i=0;i<5;i++){
        packList[packetNum].eheader->ether_dhost[i]=ethernet_protocol->ether_dhost[i];
        packList[packetNum].eheader->ether_shost[i]=ethernet_protocol->ether_shost[i];
    }




    ethernet_type = ntohs(ethernet_protocol->ether_type); /*获得以太网类型*/

    qDebug()<<"类型11111111111"<<ntohs(packList[packetNum].eheader->ether_type)<<packetNum;
    qDebug()<< "以太网类型为 :\t"<< ethernet_type;

    switch (ethernet_type)            /*判断以太网类型的值*/
    {
    case 0x0800:
        printf("网络层是：\tIPv4协议\n"); break;
    case 0x0806:
        printf("网络层是：\tARP协议\n");break;
    case 0x8035:
        printf("网络层是：\tRARP 协议\n"); break;
    default: break;
    }
    /*获得Mac源地址*/
    printf("Mac源地址:\t");
    mac_string = ethernet_protocol->ether_shost;
    printf("%02x:%02x:%02x:%02x:%02x:%02x:\n", *mac_string, *(mac_string + 1), *(mac_string + 2), *(mac_string + 3), *(mac_string + 4), *(mac_string + 5));

    /*获得Mac目的地址*/
    printf("Mac目的地址:\t");
    mac_string = ethernet_protocol->ether_dhost;
    printf("%02x:%02x:%02x:%02x:%02x:%02x:\n", *mac_string, *(mac_string + 1), *(mac_string + 2), *(mac_string + 3), *(mac_string + 4), *(mac_string + 5));

    ip_protocol_packet_callback(argument, packet_header, packet_content);


//    switch (ethernet_type)
//    {
//    case 0x0800:
//        /*如果上层是IPv4ip协议,就调用分析ip协议的函数对ip包进行贩治*/
//        ip_protocol_packet_callback(argument, packet_header, packet_content);
//        break;
//    default:break;
//    }

}


void MainWindow::tableInit()
{
    ui->tbwgt_link->verticalHeader()->setHidden(true);
    ui->tbwgt_link->horizontalHeader()->setHidden(true);
    ui->tbwgt_link->setColumnCount(2);
    ui->tbwgt_link->setRowCount(5);
    ui->tbwgt_link->setColumnWidth(0,160);
    ui->tbwgt_link->setColumnWidth(1,160);
    ui->tbwgt_link->setEditTriggers(QAbstractItemView::NoEditTriggers);

    ui->tbwgt_link->setSpan(0,0,1,4);

    ui->tbwgt_link->setItem(0,0, new QTableWidgetItem("链路层 以太网协议"));
    ui->tbwgt_link->setItem(1,0, new QTableWidgetItem("以太网类型:"));
    ui->tbwgt_link->setItem(2,0, new QTableWidgetItem("网络层:"));
    ui->tbwgt_link->setItem(3,0, new QTableWidgetItem("Mac原地址:"));
    ui->tbwgt_link->setItem(4,0, new QTableWidgetItem("Mac目的地址:"));


    //网络层
    ui->tbwgt_net->verticalHeader()->setHidden(true);
    ui->tbwgt_net->horizontalHeader()->setHidden(true);
    ui->tbwgt_net->setColumnCount(2);
    ui->tbwgt_net->setRowCount(12);
    ui->tbwgt_net->setEditTriggers(QAbstractItemView::NoEditTriggers);
    ui->tbwgt_net->setColumnWidth(0,140);
    ui->tbwgt_net->setColumnWidth(1,140);
    ui->tbwgt_net->setSpan(0,0,1,11);


    ui->tbwgt_net->setItem(0,0, new QTableWidgetItem("网络层 IP协议"));
    ui->tbwgt_net->setItem(1,0, new QTableWidgetItem("IP版本"));
    ui->tbwgt_net->setItem(2,0, new QTableWidgetItem("IP首部长度"));
    ui->tbwgt_net->setItem(3,0, new QTableWidgetItem("服务类型"));
    ui->tbwgt_net->setItem(4,0, new QTableWidgetItem("总长度"));
    ui->tbwgt_net->setItem(5,0, new QTableWidgetItem("标识"));
    ui->tbwgt_net->setItem(6,0, new QTableWidgetItem("片偏移"));
    ui->tbwgt_net->setItem(7,0, new QTableWidgetItem("生存时间"));
    ui->tbwgt_net->setItem(8,0, new QTableWidgetItem("首部校验和"));
    ui->tbwgt_net->setItem(9,0, new QTableWidgetItem("源IP"));
    ui->tbwgt_net->setItem(10,0, new QTableWidgetItem("目的IP"));
    ui->tbwgt_net->setItem(11,0, new QTableWidgetItem("协议号"));
    //运输层


    ui->tbwgt_trans->verticalHeader()->setHidden(true);
    ui->tbwgt_trans->horizontalHeader()->setHidden(true);
    ui->tbwgt_trans->setColumnCount(2);
    ui->tbwgt_trans->setRowCount(12);
    ui->tbwgt_trans->setEditTriggers(QAbstractItemView::NoEditTriggers);
    ui->tbwgt_trans->setColumnWidth(0,220);
    ui->tbwgt_trans->setColumnWidth(1,220);
    for (int i = 0;i<12;i++) {
        ui->tbwgt_trans->setRowHeight(i,34);
    }

    ui->tbwgt_trans->setSpan(0,0,1,11);

    ui->tbwgt_trans->setItem(0,0, new QTableWidgetItem("运输层 TCP协议"));
    ui->tbwgt_trans->setItem(1,0, new QTableWidgetItem("源端口"));
    ui->tbwgt_trans->setItem(2,0, new QTableWidgetItem("目的端口"));
    ui->tbwgt_trans->setItem(3,0, new QTableWidgetItem("应用层协议"));
    ui->tbwgt_trans->setItem(4,0, new QTableWidgetItem("序列号"));
    ui->tbwgt_trans->setItem(5,0, new QTableWidgetItem("确认号"));
    ui->tbwgt_trans->setItem(6,0, new QTableWidgetItem("首部长度"));
    ui->tbwgt_trans->setItem(7,0, new QTableWidgetItem("保留字段"));
    ui->tbwgt_trans->setItem(8,0, new QTableWidgetItem("控制位"));
    ui->tbwgt_trans->setItem(9,0, new QTableWidgetItem("窗口大小"));
    ui->tbwgt_trans->setItem(10,0, new QTableWidgetItem("检验和"));
    ui->tbwgt_trans->setItem(11,0, new QTableWidgetItem("紧急指针字段"));
}

int MainWindow::macInit(pcap_t *adhandle)
{
    pcap_if_t  *alldevs;
    pcap_if_t *d;

    int i = 0;

    char errbuf[PCAP_ERRBUF_SIZE];

    /* 获得网卡的列表 */
    if (pcap_findalldevs(&alldevs, errbuf) == -1)
    {
        exit(1);
    }

    /* 打印网卡信息 */
    for (d = alldevs; d; d = d->next)
    {
        ui->cmbBox_mac->addItem(d->description);
        i++;
        //        if (d->description)
        //            printf(" (%s)\n", d->description);
        //        else
        //            printf(" (No description available)\n");
    }

    if (i == 0)
    {
        printf("\n没有发现接口!确保安装了LibPcap.\n");
        return -1;
    }


    return 0;
}

void MainWindow::updateTable(int index)
{
    index = index+1;
    if(index>=1&&index<=packetNum)
    {
        u_int  header_length;    /*长度*/
        u_int  offset;                   /*片偏移*/
        u_char  tos;                     /*服务类型*/
        u_int16_t checksum;    /*首部检验和*/

        u_short ethernet_type;
        ethernet_type = ntohs(packList[index].eheader->ether_type);
        //QString temp = QString::number(packList[index].eheader->ether_type);
        ui->tbwgt_link->setItem(1,1, new QTableWidgetItem(QString::number(packList[index].eheader->ether_type)));

        //ui->tbwgt_link->setItem(1,1, new QTableWidgetItem(QString::number(packList[index].iheader->ip_version)));
        checksum = ntohs(packList[index].iheader->ip_checksum);      /*获得校验和*/
        header_length = packList[index].iheader->ip_header_length * 4; /*获得长度*/
        tos = packList[index].iheader->ip_tos;    /*获得tos*/
        offset = ntohs(packList[index].iheader->ip_off);   /*获得偏移量*/


        switch (ethernet_type)            /*判断以太网类型的值*/
        {
        case 0x0800:
            ui->tbwgt_link->setItem(2,1,new QTableWidgetItem("IPv4协议"));
            ui->tbwgt_net->setItem(1,1,new QTableWidgetItem("IPv4"));

            ui->tbwgt_net->setItem(2,1,new QTableWidgetItem(QString::number(header_length)));

            ui->tbwgt_net->setItem(3,1,new QTableWidgetItem(QString::number(tos)));

            ui->tbwgt_net->setItem(4,1,new QTableWidgetItem(QString::number(packList[index].iheader->ip_length)));

            ui->tbwgt_net->setItem(5,1,new QTableWidgetItem(QString::number(packList[index].iheader->ip_id)));

            ui->tbwgt_net->setItem(6,1,new QTableWidgetItem(QString::number((offset & 0x1fff) * 8)));

            ui->tbwgt_net->setItem(7,1,new QTableWidgetItem(QString::number(packList[index].iheader->ip_ttl)));

            ui->tbwgt_net->setItem(8,1,new QTableWidgetItem(QString::number(checksum)));

            ui->tbwgt_net->setItem(9,1,new QTableWidgetItem(inet_ntoa(packList[index].iheader->ip_source_address)));

            ui->tbwgt_net->setItem(10,1,new QTableWidgetItem(inet_ntoa(packList[index].iheader->ip_destination_address)));

            ui->tbwgt_net->setItem(11,1,new QTableWidgetItem(QString::number(packList[index].iheader->ip_protocol)));
            break;
        case 0x0806:
            ui->tbwgt_link->setItem(2,1,new QTableWidgetItem("ARP协议"));
            ui->tbwgt_net->setItem(1,1,new QTableWidgetItem("ARP"));
            break;
        case 0x8035:
            ui->tbwgt_link->setItem(2,1,new QTableWidgetItem("RARP协议"));
            ui->tbwgt_net->setItem(1,1,new QTableWidgetItem("RARP"));
            break;
        default: ui->tbwgt_link->setItem(2,1,new QTableWidgetItem("其他未定义类型"));
        }
        QString s1,s2;
        for(int i=0;i<5;i++){

            s1 += QString::number(packList[index].eheader->ether_shost[i])+":";
            s2 += QString::number(packList[index].eheader->ether_dhost[i])+":";
        }
        s1 += QString::number(packList[index].eheader->ether_shost[5]);
        s2 += QString::number(packList[index].eheader->ether_dhost[5]);
        ui->tbwgt_link->setItem(3,1,new QTableWidgetItem(s1));
        ui->tbwgt_link->setItem(4,1,new QTableWidgetItem(s2));



        if(packList[index].theader!=nullptr){
            qDebug()<<"hellloo";
            u_short source_port=ntohs(packList[index].theader->tcp_source_port);
            qDebug()<<"source_port:"<<source_port;
            u_short destination_port=ntohs(packList[index].theader->tcp_destination_port);
            qDebug()<<destination_port;
            int min = (destination_port < source_port) ? destination_port : source_port;
            qDebug()<<min;
            //空指针
//            ui->tbwgt_trans->setItem(1,1,new QTableWidgetItem(QString::number(source_port)));//源端口

//            ui->tbwgt_trans->setItem(2,1,new QTableWidgetItem(QString::number(destination_port)));//目的端口

//            ui->tbwgt_trans->setItem(3,1,new QTableWidgetItem(""));//应用层协议


            switch (min)
            {
            case 80:

                ui->tbwgt_trans->setItem(3,1,new QTableWidgetItem(" http 用于万维网（WWW）服务的超文本传输协议（HTTP）"));
                ui->tbwgt_trans->setItem(1,1,new QTableWidgetItem(QString::number(source_port)));//源端口

                ui->tbwgt_trans->setItem(2,1,new QTableWidgetItem(QString::number(destination_port)));//目的端口

                ui->tbwgt_trans->setItem(3,1,new QTableWidgetItem(""));//应用层协议
                ui->tbwgt_trans->setItem(4,1,new QTableWidgetItem(QString::number(packList[index].theader->tcp_acknowledgement)));//序列号
                ui->tbwgt_trans->setItem(5,1,new QTableWidgetItem(QString::number(packList[index].theader->tcp_ack)));//确认号
                ui->tbwgt_trans->setItem(6,1,new QTableWidgetItem(QString::number(packList[index].theader->tcp_offset * 4)));//首部长度
                ui->tbwgt_trans->setItem(7,1,new QTableWidgetItem(QString::number(packList[index].theader->tcp_reserved)));//保留字段


                ui->tbwgt_trans->setItem(8,1,new QTableWidgetItem(QString::number(packList[index].theader->tcp_flags)));//控制位

                ui->tbwgt_trans->setItem(9,1,new QTableWidgetItem(QString::number(packList[index].theader->tcp_windows)));//窗口大小
                ui->tbwgt_trans->setItem(10,1,new QTableWidgetItem(QString::number(packList[index].theader->tcp_checksum)));//检验和
                ui->tbwgt_trans->setItem(11,1,new QTableWidgetItem(QString::number(packList[index].theader->tcp_urgent_pointer)));//紧急指针字段*/
                break;
//            case 21:ui->tbwgt_trans->setItem(3,1,new QTableWidgetItem(" ftp 文件传输协议（FTP）"));
//                break;
//            case 23:ui->tbwgt_trans->setItem(3,1,new QTableWidgetItem(" telnet Telnet 服务  "));
//                break;
//            case 25:ui->tbwgt_trans->setItem(3,1,new QTableWidgetItem(" smtp 简单邮件传输协议（SMTP）"));
//                break;
//            case 110:ui->tbwgt_trans->setItem(3,1,new QTableWidgetItem(" pop3 邮局协议版本3 "));
//                break;
//            case 443:ui->tbwgt_trans->setItem(3,1,new QTableWidgetItem(" https 安全超文本传输协议（HTTP） "));
//                break;
            default://ui->tbwgt_trans->setItem(3,1,new QTableWidgetItem("【其他类型】 "));
                break;
            }

//            ui->tbwgt_trans->setItem(4,1,new QTableWidgetItem(QString::number(packList[index].theader->tcp_acknowledgement)));//序列号
//            ui->tbwgt_trans->setItem(5,1,new QTableWidgetItem(QString::number(packList[index].theader->tcp_ack)));//确认号
//            ui->tbwgt_trans->setItem(6,1,new QTableWidgetItem(QString::number(packList[index].theader->tcp_offset * 4)));//首部长度
//            ui->tbwgt_trans->setItem(7,1,new QTableWidgetItem(QString::number(packList[index].theader->tcp_reserved)));//保留字段


//            ui->tbwgt_trans->setItem(8,1,new QTableWidgetItem(QString::number(packList[index].theader->tcp_flags)));//控制位

//            ui->tbwgt_trans->setItem(9,1,new QTableWidgetItem(QString::number(packList[index].theader->tcp_windows)));//窗口大小
//            ui->tbwgt_trans->setItem(10,1,new QTableWidgetItem(QString::number(packList[index].theader->tcp_checksum)));//检验和
//            ui->tbwgt_trans->setItem(11,1,new QTableWidgetItem(QString::number(packList[index].theader->tcp_urgent_pointer)));//紧急指针字段*/


        }



    }

}






void MainWindow::on_pbt_begin_clicked()
{
    pcap_if_t  *alldevs;
    pcap_if_t *d;

    int i = 0;

    char errbuf[PCAP_ERRBUF_SIZE];

    /* 获得网卡的列表 */
    if (pcap_findalldevs(&alldevs, errbuf) == -1)
    {
        exit(1);
    }

    /* 打印网卡信息 */
    for (d = alldevs; d; d = d->next)
    {
        i++;
    }
    int inum = 0;
    inum=ui->cmbBox_mac->currentIndex()+1;
    qDebug()<<"选择网卡:"<<inum;
    /* 找到要选择的网卡结构 */
    for (d = alldevs, i = 0; i < inum - 1; d = d->next, i++);

    /* 打开选择的网卡 */
    if ((adhandle = pcap_open_live(d->name, /* 设备名称*/
                                   65536,   /* 最大值.*/
                                   /*65536允许整个包在所有mac电脑上被捕获.*/
                                   1,       /* 混杂模式*/

                                   /*
                                混杂模式是指一台主机能够接受所有经过它的数据流，不论这个数据流的目的地址是不是它，它都会接受这个数据包。也就是说，混杂模式下，网卡会把所有的发往它的包全部都接收。在这种情况下，可以接收同一集线器局域网的所有数据。
                                */
                                   1000,     /* 读超时为1m秒*/
                                   errbuf   /* error buffer*/
                                   )) == nullptr)
    {
        fprintf(stderr, "\n无法打开适配器.\t %s 不被LibPcap支持\n");
        /* Free the device list */
        pcap_freealldevs(alldevs);
    }

    /* 现在，我们不再需要设备列表, 释放它 */
    pcap_freealldevs(alldevs);
    int is_fil = 0;
    QString qstr=ui->lineEdit_filter->text();
    qDebug()<<qstr;
    string str=qstr.toStdString() ;
    if(qstr!=nullptr)
    {
        is_fil = 1;
    }

    if (is_fil == 1) {
        u_int netmask;//过滤时用的子网掩码
        struct bpf_program fcode;//pcap_compile所调用的结构体
        char packet_filter[20];//过滤字符

        cout << "\n【请输入过滤信息】:\t\t";
        //cin >> packet_filter;
        //         cin.get();
        //         cin.getline(packet_filter, 20);
        strcpy(packet_filter,str.data());



        //先获得地址的子网掩码
        if (d->addresses != nullptr)
            /* 获得接口第一个地址的掩码 */
            netmask = ((struct sockaddr_in *)(d->addresses->netmask))->sin_addr.S_un.S_addr;
        else
            /* 如果接口没有地址，那么我们假设一个C类的掩码 */
            netmask = 0xffffff;

        //pcap_compile()的原理是将高层的布尔过滤表
        //达式编译成能够被过滤引擎所解释的低层的字节码
        if (pcap_compile(adhandle,	//适配器处理对象
                         &fcode,
                         packet_filter,   //过滤ip和UDP
                         1,               //优化标志
                         netmask          //子网掩码
                         ) < 0)
        {
            //过滤出现问题
            fprintf(stderr, "\nUnable to compile the packet filter. Check the syntax.\n");
            // 释放设备列表
            pcap_freealldevs(alldevs);
        }

        //设置过滤器
        if (pcap_setfilter(adhandle, &fcode) < 0)
        {
            fprintf(stderr, "\nError setting the filter.\n");
            /* 释放设备列表 */
            pcap_freealldevs(alldevs);

        }
    }

    double dwDuration=1;
    int t=QString(ui->lineEdit_time->text()).toInt();
    if(t>0)
    {
        dwDuration=t;
    }

    time_t beg;
    time_t end;
    time(&beg);        // 获得当前系统时间

    while (1)
    {
        time(&end);            // 获得当前系统时间
        //如果捕获时间到，就结束捕获
        if (end - beg >= dwDuration)
        {
            break;
        }
        // 捕获经过网卡的IP数据包


        int issuccess = pcap_dispatch(adhandle, 1, ethernet_protocol_packet_callback, nullptr);
        if(issuccess>0){
            QString str=QString("第%1个包").arg(packetNum);
            ui->listwgt_pack->addItem(str);
        }
    }
}

void MainWindow::on_listwgt_pack_currentRowChanged(int currentRow)
{
    ui->tbwgt_link->clear();
    ui->tbwgt_net->clear();
    ui->tbwgt_trans->clear();
    tableInit();
    updateTable(currentRow);

}
